package net.ericaro.neojavagengen;

import net.ericaro.neojavagen.Literals;
import net.ericaro.neojavagen.classes.InterfaceTypes;
import net.ericaro.neojavagen.interfaces.NormalInterfaceDeclaration;
import net.ericaro.neojavagen.names.QualifiedIdentifier;
import net.ericaro.neojavagen.packages.CompilationUnit;
import net.ericaro.neojavagen.packages.ImportDeclaration;
import net.ericaro.neojavagen.packages.ImportDeclarations;
import net.ericaro.neojavagen.packages.PackageDeclaration;
import net.ericaro.neojavagen.packages.TypeDeclaration;
import net.ericaro.neojavagen.packages.TypeDeclarations;
import net.ericaro.neojavagen.types.ClassOrInterfaceType;
import net.ericaro.neojavagen.types.Identifier;
import net.ericaro.neojavagen.types.InterfaceType;
import net.ericaro.neojavagen.types.TypedIdentifier;

public abstract class AbstractPart implements Part{


	// definition
	QualifiedIdentifier qualifiedPackageName;
	TypedIdentifier nameIdentifier;
	Identifier simpleTypeName;
	private InterfaceTypes interfaceTypes;
	public void addInterfaceType(InterfaceType type){
		if (!getInterfaceTypes().contains(type))
			getInterfaceTypes().add(type);
	}
	public InterfaceTypes getInterfaceTypes() {
		if (interfaceTypes == null ) {
			interfaceTypes = new InterfaceTypes();
		}
		return interfaceTypes;
	}
	public TypedIdentifier getNameIdentifier() {
		return nameIdentifier;
	}
	
	public Identifier getSimpleTypeName() {
		return simpleTypeName;
	}
	public void setPackageName(Identifier packageName) {
		qualifiedPackageName = new QualifiedIdentifier(Literals.identifier("net"), Literals.identifier("ericaro"), Literals.identifier("neojavagen"), packageName);
	}

	public QualifiedIdentifier getQualifiedPackageName() {
		return qualifiedPackageName;
	}

	public ClassOrInterfaceType getClassOrInterfaceType() {
		ClassOrInterfaceType typedIdentifiers = new ClassOrInterfaceType();
		for (Identifier i : getQualifiedPackageName())
			typedIdentifiers.add(new TypedIdentifier(i));
		typedIdentifiers.add(getNameIdentifier());
		return typedIdentifiers;
	}

	protected CompilationUnit compilationUnit;
	protected ImportDeclarations importDeclarations;
	protected Grammar grammar;
	protected PartReference self;

	public AbstractPart(Grammar grammar, String name) {
		this(grammar);
		// could be in a single statement
		self = grammar.createPartReference(name);
		self.attach(this);
		
		
		this.nameIdentifier = new TypedIdentifier(Literals.identifier(name));
		this.simpleTypeName = Literals.identifier(name);
		
		
		setPackageName(Literals.identifier(grammar.currentPackage.toLowerCase()));

	}

	public AbstractPart(Grammar grammar) {
		super();
		this.grammar = grammar;
	}

	public CompilationUnit getCompilationUnit() {
		if (compilationUnit == null) {
			createCompilationUnit();
		}
		return compilationUnit;
	}

	private void createCompilationUnit() {
		importDeclarations = new ImportDeclarations();// keep import for later use
		// creates a compilation unit with a single type decl, as defined by sub classes
		TypeDeclaration typeDeclaration = getTypeDeclaration();
		if (typeDeclaration instanceof NormalInterfaceDeclaration)
			System.out.println("generating interface "+ getSimpleTypeName()); 
		compilationUnit = new CompilationUnit(new PackageDeclaration(getQualifiedPackageName()), importDeclarations, new TypeDeclarations(typeDeclaration));

	}

	/**
	 * used to append import from sub classes
	 * 
	 * @param importDeclaration
	 */
	protected void addImportDeclaration(ImportDeclaration importDeclaration) {
		importDeclarations.add(importDeclaration);
	}

	/**
	 * implemented by subclasses to create the type declaration
	 * 
	 * @return
	 */
	protected abstract TypeDeclaration getTypeDeclaration();

}
